package com.gallsoft.games.bennyadv;

import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.opengles.GL10;

import com.gallsoft.games.bennyadv.World.WorldListener;
import com.gallsoft.games.framework.Game;
import com.gallsoft.games.framework.Input.TouchEvent;
import com.gallsoft.games.framework.gl.Camera2D;
import com.gallsoft.games.framework.gl.TextureRegion;
import com.gallsoft.games.framework.gamedev2d.FPSCounter;
import com.gallsoft.games.framework.gamedev2d.SpriteBatcher;
import com.gallsoft.games.framework.impl.GLScreen;
import com.gallsoft.games.framework.math.OverlapTester;
import com.gallsoft.games.framework.math.Rectangle;
import com.gallsoft.games.framework.math.Vector2;

public class GameScreen extends GLScreen {

    static final int GAME_READY = 0;
    static final int GAME_RUNNING = 1;
    static final int GAME_PAUSED = 2;
    static final int GAME_LEVEL_END = 3;
    static final int GAME_OVER = 4;
    static final int DIED = 5;

    int state;
    Camera2D guiCam;
    Vector2 touchPoint;
    SpriteBatcher batcher;
    World world;
    WorldListener worldListener;
    WorldRenderer renderer;
    //Rectangle pauseBounds;
    Rectangle jumpBounds;
    Rectangle leftBounds;
    Rectangle rightBounds;
    Rectangle upBounds;
    TextureRegion itemImage;
    //Rectangle resumeBounds;
    //Rectangle quitBounds;
    long lastScore;
    int nextLevel = 12;
    int maxLevel = 12;
    int lives = 3;
    int numItems;
    int itemsCollected;
    long currentScore = 0;
    long bonus, oldScore, total;
    String scoreAsString = "00000";
    String scoreFormat = String.format("%%0%dd", 5);;
    String timerFormat = String.format("%%0%dd", 3);;

    List<Item> itemsCurrent = new ArrayList<Item>();
    List<Scenery> switchesCurrent = new ArrayList<Scenery>();
    List<Platform> movingPlatformsCurrent = new ArrayList<Platform>();
    List<Scenery> doorsCurrent = new ArrayList<Scenery>();
    List<Scenery> keysCurrent = new ArrayList<Scenery>();

    int scoreX = 50;
    int scoreY = 290;
    FPSCounter fpsCounter;
    boolean[] touchControls = new boolean[5];
    
    float deltaTime;
    long startTime;

    public GameScreen(Game game) {
        super(game);
        // state = GAME_READY;
        state = GAME_RUNNING;
        guiCam = new Camera2D(glGraphics, 480, 320);
        touchPoint = new Vector2();
        batcher = new SpriteBatcher(glGraphics, 1000);
        worldListener = new WorldListener() {

            @Override
            public void jump() {
                Assets.playSound(Assets.jumpSound);
            }

            @Override
            public void highJump() {
                // Assets.playSound(Assets.highJumpSound);
            }

            @Override
            public void hit() {
                Assets.playSound(Assets.hitSound);
            }

            @Override
            public void coin() {
                Assets.playSound(Assets.coinSound);
            }
        };
        
        //nextLevel = 1;
        world = new World(worldListener, game.getFileIO(), nextLevel);
        
        world.score = currentScore;
        world.lives = lives;
        world.itemsCollected = itemsCollected;

        renderer = new WorldRenderer(glGraphics, batcher, world);
        //pauseBounds = new Rectangle(320 - 64, 480 - 64, 64, 64);
        
        jumpBounds = new Rectangle(0, 0, 250, 320);
        leftBounds = new Rectangle(480 - 180, 40, 80, 80);
        rightBounds = new Rectangle(420, 40, 80, 80);
        upBounds = new Rectangle(320, 100, 80, 80);
        
        //resumeBounds = new Rectangle(160 - 96, 240, 192, 36);
        //quitBounds = new Rectangle(160 - 96, 240 - 36, 192, 36);
        lastScore = 0;
        currentScore = 0;
        numItems = world.items.size();
        itemImage = world.items.get(0).getTexture();
        
        fpsCounter = new FPSCounter();
        
        touchControls[0] = false;
        touchControls[1] = false;
        touchControls[2] = false;
        touchControls[3] = false;
        touchControls[4] = false;
    }

    @Override
    public void update(float deltaTime) {
        if (deltaTime > 0.1f)
            deltaTime = 0.1f;

        switch (state) {
            case GAME_READY:
                updateReady();
                break;
            case GAME_RUNNING:
                updateRunning(deltaTime);
                break;
            case GAME_PAUSED:
                updatePaused();
                break;
            case GAME_LEVEL_END:
                updateLevelEnd();
                break;
            case GAME_OVER:
                updateGameOver();
                break;
            case DIED:
                updateDied();
                break;
        }
    }

    private void updateReady() {
        if (game.getInput().getTouchEvents().size() > 0) {
            state = GAME_RUNNING;
        }
    }

    private void updateRunning(float deltaTime) {
        List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
        
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            
            //if (event.type != TouchEvent.TOUCH_UP)
            //    continue;
            
            if (event.type == TouchEvent.TOUCH_DRAGGED)
                continue;

            touchPoint.set(event.x, event.y);
            guiCam.touchToWorld(touchPoint);

            /*
            if (OverlapTester.pointInRectangle(pauseBounds, touchPoint)) {
                Assets.playSound(Assets.clickSound);
                state = GAME_PAUSED;
                return;
            }
            */
            if (event.type == TouchEvent.TOUCH_DOWN) {
                if (OverlapTester.pointInRectangle(jumpBounds, touchPoint)) {
                    //Assets.playSound(Assets.clickSound);
                    touchControls[0] = true;
                }
                else if (OverlapTester.pointInRectangle(leftBounds, touchPoint)) {
                    touchControls[1] = true;
                }
                else if (OverlapTester.pointInRectangle(rightBounds, touchPoint)) {
                    touchControls[2] = true;
                }
                else if (OverlapTester.pointInRectangle(upBounds, touchPoint)) {
                    touchControls[3] = true;
                } 
            }
            else if (event.type == TouchEvent.TOUCH_UP) {
                if (OverlapTester.pointInRectangle(jumpBounds, touchPoint)) {
                    touchControls[0] = false;
                }
                else if (OverlapTester.pointInRectangle(leftBounds, touchPoint)) {
                    touchControls[1] = false;
                }
                else if (OverlapTester.pointInRectangle(rightBounds, touchPoint)) {
                    touchControls[2] = false;
                }                
                else if (OverlapTester.pointInRectangle(upBounds, touchPoint)) {
                    touchControls[3] = false;
                }                
            }
        }

        //world.update(deltaTime, game.getInput().getAccelX());
        world.update(deltaTime, game.getInput(), touchControls);

        if (world.score != currentScore) {
            currentScore = world.score;
            itemsCollected = world.itemsCollected;
            //currentScore = "" + lastScore;
            //scoreFormat = String.format("%%0%dd", 6);
            scoreAsString = String.format(scoreFormat, currentScore);
        }
        
        keysCurrent = world.keys;
        
        if (world.state == World.WORLD_STATE_NEXT_LEVEL) {
            bonus = world.timer * 10;
            oldScore = currentScore;
            total = currentScore;
            currentScore = currentScore + bonus;
            state = GAME_LEVEL_END;
            startTime = System.nanoTime();            
        }        
        else if (world.state == World.WORLD_STATE_DIED) {
            lives = world.lives;
            state = DIED;
        }
        else if (world.state == World.WORLD_STATE_GAME_OVER) {
                state = GAME_OVER;

            //if (lastScore >= Settings.highscores[4])
            //    currentScore = "new highscore: " + lastScore;
            //else
            //    currentScore = "score: " + lastScore;
            //Settings.addScore(lastScore);
            //Settings.save(game.getFileIO());
        }
    }

    private void updatePaused() {
        List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
        
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            
            if (event.type != TouchEvent.TOUCH_UP)
                continue;

            touchPoint.set(event.x, event.y);
            guiCam.touchToWorld(touchPoint);

            /*
            if (OverlapTester.pointInRectangle(resumeBounds, touchPoint)) {
                Assets.playSound(Assets.clickSound);
                state = GAME_RUNNING;
                return;
            }

            if (OverlapTester.pointInRectangle(quitBounds, touchPoint)) {
                Assets.playSound(Assets.clickSound);
                game.setScreen(new MainMenuScreen(game));
                return;

            }
            */
        }
    }

    private void updateLevelEnd() {
        List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            if (event.type != TouchEvent.TOUCH_UP)
                continue;
            
            state = GAME_RUNNING;
            nextLevel = world.level + 1;
            
            if (nextLevel > maxLevel)
                nextLevel = 1;
            
            world = new World(worldListener, game.getFileIO(), nextLevel);
            
            numItems = world.items.size();
            itemImage = world.items.get(0).getTexture();
            itemsCollected = 0;
            
            world.score = currentScore;
            world.lives = lives;
            world.itemsCollected = itemsCollected;

            renderer = new WorldRenderer(glGraphics, batcher, world);
            
            /*
            world = new World(worldListener, game.getFileIO(), nextLevel);
            renderer = new WorldRenderer(glGraphics, batcher, world);
            world.score = lastScore;
            //world.level = nextLevel;
            //state = GAME_READY;
            */
            
            
            //game.setScreen(new GameScreen(game));
        }
    }

    private void updateGameOver() {
        List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            if (event.type != TouchEvent.TOUCH_UP)
                continue;
            game.setScreen(new MainMenuScreen(game));
            //game.setScreen(new GameScreen(game));
        }
    }

    private void updateDied() {
        List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
        int len = touchEvents.size();
        for (int i = 0; i < len; i++) {
            TouchEvent event = touchEvents.get(i);
            if (event.type != TouchEvent.TOUCH_UP)
                continue;
            
            state = GAME_RUNNING;
            saveGameState();
            world = new World(worldListener, game.getFileIO(), nextLevel);
            restoreGameState();
            world.score = currentScore;
            world.lives = lives;
            world.itemsCollected = itemsCollected;
            world.doors = doorsCurrent;
            world.keys = keysCurrent;
            
            renderer = new WorldRenderer(glGraphics, batcher, world);
        }
    }

    private void saveGameState() {
        itemsCurrent = world.items;
        switchesCurrent = world.switches;
        movingPlatformsCurrent = world.movingPlatforms;
        doorsCurrent = world.doors;
        keysCurrent = world.keys;
    }

    private void restoreGameState() {
        world.items = itemsCurrent;
        world.switches = switchesCurrent;
        world.movingPlatforms = movingPlatformsCurrent;
    }
    
    @Override
    public void present(float deltaTime) {
        // Render game objects
        GL10 gl = glGraphics.getGL();
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        gl.glEnable(GL10.GL_TEXTURE_2D);

        renderer.render();            

        // Render HUD
        guiCam.setViewportAndMatrices();
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        batcher.beginBatch(Assets.items);

        int len = world.messages.size();
        
        for (int i = 0; i < len; i++) {
            DisplayMessage displayMessage = world.messages.get(i);
            Assets.font.drawText(batcher, displayMessage.message, displayMessage.x, displayMessage.y);
        }

        batcher.drawSprite(60, 310, 96, 32, Assets.scoreString);        
        batcher.drawSprite(412, 310, 64, 32, Assets.timeString);        
        batcher.drawSprite(329, 310, 96, 32, Assets.levelString);   
        
        batcher.drawSprite(168, 284, 32, 32, itemImage);        
        batcher.drawSprite(168, 315, 64, 32, Assets.livesIcon);        

        for (int i = 0; i < keysCurrent.size(); i++) {
            Scenery key = keysCurrent.get(i);
            if (key.state) {
                batcher.drawSprite(459, 310 - (i * 32), 32, 32, key.sceneryGraphic);
            }
        }
        
        Assets.font.drawText(batcher, scoreAsString, 30, 290);
        Assets.font.drawText(batcher, "" + nextLevel, 326, 290);
        Assets.font.drawText(batcher, "" + String.format(timerFormat, world.timer), 395, 290);
        Assets.font.drawText(batcher, "= " + (lives - 1), 194, 310);
        Assets.font.drawText(batcher, "= " + itemsCollected + "/" + numItems, 194, 290);

        switch (state) {
            case GAME_READY:
                presentReady();
                break;
            case GAME_RUNNING:
                presentRunning();
                break;
            case GAME_PAUSED:
                presentPaused();
                break;
            case GAME_LEVEL_END:
                presentLevelEnd();
                break;
            case GAME_OVER:
                presentGameOver();
                break;
        }
        batcher.endBatch();
        gl.glDisable(GL10.GL_BLEND);
        fpsCounter.logFrame();
    }

    private void presentReady() {
        // batcher.drawSprite(160, 240, 192, 32, Assets.ready);
    }

    private void presentRunning() {
    }

    private void presentPaused() {
        // batcher.drawSprite(160, 240, 192, 96, Assets.pauseMenu);
    }

    private void presentLevelEnd() {
        batcher.drawSprite(245, 160, 384, 192, Assets.messageBackground);
        
        Assets.font.drawText(batcher, "Well Done!", 190, 220);
        Assets.font.drawText(batcher, "Score: " + oldScore, 80, 170);
        Assets.font.drawText(batcher, "Bonus: " + world.timer + " x 10 = " + bonus, 80, 140);
        
        //if (total < currentScore) {
        //    deltaTime = (System.nanoTime() - startTime) / 1000000000.0f;
            
        //    if (deltaTime > 0.001f) {
        //        total += 10;
        //        Assets.playSound(Assets.clickSound);
        //        startTime = System.nanoTime();
        //    }
        //    Assets.font.drawText(batcher, "Total: " + total, 80, 110);
        //}
        //else
            Assets.font.drawText(batcher, "Total: " + currentScore, 80, 110);
    }

    private void presentGameOver() {
        // batcher.drawSprite(160, 240, 160, 96, Assets.gameOver);
    }

    @Override
    public void pause() {
        if (state == GAME_RUNNING)
            state = GAME_PAUSED;
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
    }
}
